/*
 * Manejo de archivos XMLs y todo lo que involucra la inicializacion
 * de procesos en el simulador.
 * Es la primera clase usada al correr el proyecto.
 */

package Estructuras;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.ArrayList;
import java.util.LinkedList;

/*
 * Explicacion de los atributos del XML:
 *      ProcessInfo: define el alcance del XML
 *          Process: contiene la informacion basica por cada proceso
 *              ProcessType: indica el tipo de proceso
 *              Priority: Prioridad real del proceso.
 *              ArrivalTime: tiempo de llegada del proceso (momento de
 *                            creacion).
 *              Requirements: engloba los requerimientos del proceso.
 *                  Resource: define la utilizacion y tiempo de los recursos.
 *                      ResourceType: Tipo del Recurso(IO o CPU).
 *                      UseTime: Tiempo en TICKS del recurso.
 *                      
 */


/**
 *
 * @author Cesar Hernandez
 */

public class process_xml {

    private Document documento;

    public process_xml(String rutaXML){
        try{
            
           DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance( );
           DocumentBuilder builder = factory.newDocumentBuilder();
           this.documento = builder.parse( new File(rutaXML) );
            documento.getDocumentElement().normalize();

        }catch (Exception e){
           // Algún tipo de error: fichero no accesible, formato de XML incorrecto, etc.
            System.out.println(rutaXML);
        }
    }

    public void construirProceso(Task_struct proceso, String ProcessType,
            String Priority, String ArrivalTime, ArrayList<Integer> cpu_time,
            ArrayList<Integer> io_time, ArrayList<String> trace){

        /* Establece la prioridad del proceso*/

        if (ProcessType.trim().equalsIgnoreCase("RoundRobin")){
            proceso.setPolicy(Task_struct.RR);
        }else if(ProcessType.trim().equalsIgnoreCase("RealTime")){

            proceso.setPolicy(Task_struct.REALTIME);
        }else if(ProcessType.trim().equalsIgnoreCase("Normal")){

            proceso.setPolicy(Task_struct.NORMAL);
        }

        proceso.setPrio((new Integer(Priority.trim())).shortValue());
        proceso.setArrivalTime((new Integer(ArrivalTime.trim())).shortValue());
        proceso.setCputime(cpu_time);
        proceso.setIOtime(io_time);
        proceso.setTrace(trace);
    }

    public boolean esCpu(String recurso){

        if (recurso.trim().equalsIgnoreCase("IO")){

            return false;
        }else if (recurso.trim().equalsIgnoreCase("CPU")){
            return true;
        }

        return true;
    }

    /*
     * Lee el archivo XML y va obteniendo su informacion.
     * Devuelve la lista de procesos que se van a cargar en el sistema
     * segun su ArrivalTime.
     */
    public LinkedList<Task_struct> lecturaXML(){

        Node nodoRaiz = documento.getFirstChild(); //Obtiene el ProcessInfo
        Element processinfo = (Element) nodoRaiz;
        LinkedList<Task_struct> lista_inicial = new LinkedList<Task_struct>();
        ArrayList<Integer> cpu_time = new ArrayList<Integer>();
        ArrayList<Integer> io_time = new ArrayList<Integer>();
        ArrayList<String> trace = new ArrayList<String>();

        // Se cargan los hijos de ProcessInfo, los cuales representan
        // cada uno un proceso diferente a simular.

        NodeList procesos = processinfo.getElementsByTagName("Process");
        //System.out.println("Procesos numeros: "+procesos.getLength());
        for(int i = 0; i < procesos.getLength(); i++){

            // Por cada proceso del XML creamos su PCB
            Task_struct proceso_final = new Task_struct();
            
            // Obtenemos cada proceso del XML a fin de determinar
            // su informacion.
            Node procesoTemp = procesos.item(i);

            NodeList procesoDetalles5= ((Element) procesoTemp).getElementsByTagName("ProcessType").item(0).getChildNodes();
            Node ProcessType = (Node) procesoDetalles5.item(0);
            NodeList procesoDetalles2= ((Element) procesoTemp).getElementsByTagName("Priority").item(0).getChildNodes();
            Node Priority = (Node) procesoDetalles2.item(0);
            NodeList procesoDetalles3= ((Element) procesoTemp).getElementsByTagName("ArrivalTime").item(0).getChildNodes();
            Node ArrivalTime = (Node) procesoDetalles3.item(0);

            //Node reqDetalles= ((Element) procesoTemp).getElementsByTagName("Requirements").item(0);

            NodeList Requirements = ((Element) procesoTemp).getElementsByTagName("Requirements");
            Node reqTemp = (Node) Requirements.item(0);
            NodeList Resources = ((Element) reqTemp).getElementsByTagName("Resource");

            /*
            System.out.println(ProcessType.getNodeValue());
            System.out.println(Priority.getNodeValue());
            System.out.println(ArrivalTime.getNodeValue());
             *
             */
            for (int j = 0; j < Resources.getLength(); j++){

                Node recurso = Resources.item(j);
                NodeList recursoDetalles = ((Element) recurso).getElementsByTagName("ResourceType").item(0).getChildNodes();
                Node ResourceType = (Node) recursoDetalles.item(0);
                NodeList recursoDetalles2 = ((Element) recurso).getElementsByTagName("UseTime").item(0).getChildNodes();
                Node UseTime = (Node) recursoDetalles2.item(0);
                //System.out.println("ResourceType: "+ResourceType.getNodeValue());
                //System.out.println("UseTime: "+UseTime.getNodeValue());

                if (esCpu(ResourceType.getNodeValue())){

                    cpu_time.add(new Integer(UseTime.getNodeValue().trim()));
                    trace.add("CPU");
                }else{

                    io_time.add(new Integer(UseTime.getNodeValue().trim()));
                    trace.add("IO");
                }
            }

            construirProceso(proceso_final,ProcessType.getNodeValue(),
                    Priority.getNodeValue(),ArrivalTime.getNodeValue(),
                    cpu_time, io_time, trace); // Se construye la informacion del proceso

            lista_inicial.add(proceso_final); // Se agrega a la lista inicial de procesos.
        }

        return lista_inicial;
    }
}


